import { ts, SwitchStatement, rule, BreakStatement, is, CallExpression, BinaryExpression } from "qvog-dsl";

const SEVERITY = 2;
const DOC_PATH = 'docs/use-isnan-check.md';

function isSpecificId(node: ts.Node, name: string): boolean {
    return ts.isIdentifier(node) && node.text === name;
}

function isSpecificMemberAccess(node: ts.Node, objectName: string, propertyName: string): boolean {
    return (ts.isPropertyAccessExpression(node) &&
            ts.isIdentifier(node.expression) && node.expression.text === objectName &&
            ts.isIdentifier(node.name) && node.name.text === propertyName) ||
        (ts.isElementAccessExpression(node) &&
            ts.isIdentifier(node.expression) && node.expression.text === objectName &&
            ts.isStringLiteral(node.argumentExpression) && node.argumentExpression.text === propertyName);
}

function isNaNIdentifier(node: ts.Node): boolean {
    if (ts.isParenthesizedExpression(node)) {
        let express = node.expression;
        if (ts.isBinaryExpression(express)) {
            return isNaNIdentifier(express.right);
        }
        return isNaNIdentifier(express);
    }

    return isSpecificId(node, 'NaN') || isSpecificMemberAccess(node, 'Number', 'NaN');
}

export default rule({ description: '' })
    .match(SwitchStatement)
    .when((node, { props }): boolean => {
        if (isNaNIdentifier(node.expression)) {
            props.description = "'switch(NaN)' can never match a case clause. Use Number.isNaN instead of the switch";
            return true;
        }
        for (const switchCase of node.caseBlock.clauses) {
            if ((switchCase as ts.CaseClause).expression && isNaNIdentifier((switchCase as ts.CaseClause).expression)) {
                props.description = "'case NaN' can never match. Use Number.isNaN before the switch";
                return true;
            }
        }
        return false;
    })
    .report((node, { api, props }) => {
        api.report({
            location: api.getLocation(node),
            severity: SEVERITY,
            description: props.description,
            docPath: DOC_PATH,
        });
    });
